package cn.bugstack.springframework.beans.factory.support;

import cn.bugstack.springframework.beans.BeansException;
import cn.bugstack.springframework.beans.factory.DisposableBean;
import cn.bugstack.springframework.beans.factory.config.BeanDefinition;
import cn.hutool.core.util.StrUtil;

import java.lang.reflect.Method;

/**
 * 这段代码是一个 DisposableBeanAdapter 类的实现，用于封装单个 bean 的销毁逻辑。
 * 构造方法接收一个 bean 对象、bean 的名称和 bean 的定义。
 * 在销毁时，首先检查 bean 是否实现了 DisposableBean 接口，如果是，则调用其 destroy() 方法进行销毁。
 * 接着，检查是否存在自定义的销毁方法，如果存在且不是实现了 DisposableBean 接口的默认方法，则通过反射调用该方法。
 * 这样做的目的是为了兼容两种不同的销毁方式：
 *      一种是实现 DisposableBean 接口的方式。
 *      另一种是通过 destroy-method 属性配置的方式。同时，通过检查是否存在自定义销毁方法，避免了重复执行销毁操作。
 * 总之，DisposableBeanAdapter 类负责统一管理单个 bean 的销毁操作，保证在 Spring 容器关闭时能够正确地释放资源和清理状态。
 */
public class DisposableBeanAdapter implements DisposableBean {

    private final Object bean;
    private final String beanName;
    private String destroyMethodName;

    public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) {
        this.bean = bean;
        this.beanName = beanName;
        this.destroyMethodName = beanDefinition.getDestroyMethodName();
    }

    @Override
    public void destroy() throws Exception {
        // 1. 实现接口 DisposableBean
        if (bean instanceof DisposableBean) {
            ((DisposableBean) bean).destroy();
        }

        // 2. 注解配置 destroy-method {判断是为了避免二次执行销毁}
        if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean /*&& "destroy".equals(this.destroyMethodName)*/)) {
            Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
            if (null == destroyMethod) {
                throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
            }
            destroyMethod.invoke(bean);
        }
        
    }

}
